package org.chen.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.chen.enu.TaskStatus;
import org.chen.exception.ServiceException;
import org.chen.mapper.CommentTaskMapper;
import org.chen.model.CommentBatch;
import org.chen.model.CommentTask;
import org.chen.request.BatchCommentRequestDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class TaskCreationService {

    @Autowired
    private CommentTaskMapper taskMapper;

    /**
     * 创建单个评论任务
     */
    private CommentTask createCommentTask(String batchNo, CommentBatch batch, String url) {
        CommentTask task = new CommentTask();
        task.setId(IdWorker.getId());
        task.setBatchNo(batchNo);
        task.setCommentContent(batch.getCommentContent());
        task.setNickname(batch.getNickname());
        task.setEmail(batch.getEmail());
        task.setWebsiteUrl(batch.getWebsiteUrl());
        task.setTargetUrl(url);
        task.setStatus(TaskStatus.PENDING.name());
        task.setRetryCount(0);
        task.setCreateTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());
        return task;
    }

    /**
     * 创建并插入批次任务 - 分片批量插入优化版
     */
    @Transactional(rollbackFor = Exception.class)
    public void createBatchTasks(String batchNo, CommentBatch batch, List<String> targetUrls) {
        if (CollectionUtils.isEmpty(targetUrls)) {
            return;
        }

        try {
            // 1. 预先分配ID并按分片分组
            Map<Integer, List<CommentTask>> shardingGroups = new HashMap<>();
            for (String url : targetUrls) {
                CommentTask task = createCommentTask(batchNo, batch, url);
                // 使用ID确定分片
                int shardingKey = Math.toIntExact(task.getId() % 16);
                shardingGroups.computeIfAbsent(shardingKey, k -> new ArrayList<>()).add(task);
            }

            // 2. 对每个分片组分别进行批量插入
            for (Map.Entry<Integer, List<CommentTask>> entry : shardingGroups.entrySet()) {
                List<CommentTask> groupedTasks = entry.getValue();
                // 每组内再按100条一批处理
                Lists.partition(groupedTasks, 100).forEach(partition -> {
                    try {
                        taskMapper.batchInsert(partition);
                    } catch (Exception e) {
                        log.error("Batch insert failed for sharding key: {}, size: {}, error: {}",
                                entry.getKey(), partition.size(), e.getMessage());
                        // 降级为单条插入
                        handleBatchInsertFailure(partition);
                    }
                });
            }
        } catch (Exception e) {
            log.error("Failed to create batch tasks, batchNo: {}, error: {}", batchNo, e.getMessage());
            throw new ServiceException("创建批量任务失败: " + e.getMessage());
        }
    }

    /**
     * 创建批次记录
     */
    public CommentBatch createBatchRecord(String batchNo, BatchCommentRequestDTO request) {
        CommentBatch batch = new CommentBatch();
        batch.setBatchNo(batchNo);
        batch.setTotalCount(request.getTargetUrls().size());
        batch.setSuccessCount(0);
        batch.setFailureCount(0);
        batch.setCommentContent(request.getCommentContent());
        batch.setNickname(request.getNickname());
        batch.setEmail(request.getEmail());
        batch.setWebsiteUrl(request.getWebsiteUrl());
        batch.setStatus(TaskStatus.PENDING.name());
        batch.setCreateTime(LocalDateTime.now());
        batch.setUpdateTime(LocalDateTime.now());
        return batch;
    }

    /**
     * 批量插入失败时的降级处理 - 单条插入
     */
    private void handleBatchInsertFailure(List<CommentTask> tasks) {
        for (CommentTask task : tasks) {
            try {
                taskMapper.insert(task);  // 使用MyBatis-Plus的save方法
            } catch (Exception e) {
                log.error("Single insert failed for task with batchNo: {}, error: {}",
                        task.getBatchNo(), e.getMessage());
                throw new ServiceException("单条插入失败: " + e.getMessage());
            }
        }
    }
}
